home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1995 March / Macworld CD-ROM (March 1995).cdr / Updaters / Symantec C++ 6.0.1 Update / Library Updates / Standard Libraries / C sources / printf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-13  |  9.4 KB  |  508 lines  |  [TEXT/KAHL]

  1.  
  2. /*
  3.  *  printf.c
  4.  *
  5.  *  Copyright (c) 1991 Symantec Corporation.  All rights reserved.
  6.  *
  7.  */
  8.  
  9. #include "stdio.h"
  10. #include "stdarg.h"
  11. #include "string.h"
  12. #include "ansi_private.h"
  13. #include <SANE.h>
  14.  
  15. #define BUFLEN            512
  16. #define TRUE            1
  17. #define FALSE            0
  18.  
  19. static struct format {
  20.     unsigned         leftJustify : 1;
  21.     unsigned         forceSign : 1;
  22.     unsigned         altForm : 1;
  23.     unsigned         zeroPad : 1;
  24.     unsigned         havePrecision : 1;
  25.     unsigned         hSize : 1;
  26.     unsigned         lSize : 1;
  27.     unsigned         LSize : 1;
  28.     char            sign;
  29.     char            exponent;
  30.     int                fieldWidth;
  31.     int                precision;
  32. } default_format;
  33.  
  34.  
  35. struct decrec {
  36.     char            sgn;
  37.     short            exp;
  38.     char            sig[SIGDIGLEN];
  39.     short            pad;
  40.     /* following fields aren't used by SANE */
  41.     short            min;
  42.     short            dot;
  43.     short            max;
  44. };
  45.  
  46. static void ftod(int, int, struct decrec *, long double);
  47.  
  48.  
  49. int
  50. vfprintf(FILE *fp, const char *fmt, va_list arg)
  51. {
  52.     register int c, i, j, nwritten = 0;
  53.     register unsigned long n;
  54.     long double x;
  55.     register char *s;
  56.     char buf[BUFLEN], *digits, *t;
  57.     struct format F;
  58.     struct decrec D;
  59.     
  60.     for (c = *fmt; c; c = *++fmt) {
  61.         if (c != '%')
  62.             goto copy1;
  63.         F = default_format;
  64.         
  65.             /*  decode flags  */
  66.             
  67.         for (;;) {
  68.             c = *++fmt;
  69.             if (c == '-')
  70.                 F.leftJustify = TRUE;
  71.             else if (c == '+')
  72.                 F.forceSign = TRUE;
  73.             else if (c == ' ')
  74.                 F.sign = ' ';
  75.             else if (c == '#')
  76.                 F.altForm = TRUE;
  77.             else if (c == '0')
  78.                 F.zeroPad = TRUE;
  79.             else
  80.                 break;
  81.         }
  82.         
  83.             /*  decode field width  */
  84.             
  85.         if (c == '*') {
  86.             if ((F.fieldWidth = va_arg(arg, int)) < 0) {
  87.                 F.leftJustify = TRUE;
  88.                 F.fieldWidth = -F.fieldWidth;
  89.             }
  90.             c = *++fmt;
  91.         }
  92.         else {
  93.             for (; c >= '0' && c <= '9'; c = *++fmt)
  94.                 F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
  95.         }
  96.         
  97.             /*  decode precision  */
  98.             
  99.         if (c == '.') {
  100.             if ((c = *++fmt) == '*') {
  101.                 F.precision = va_arg(arg, int);
  102.                 c = *++fmt;
  103.             }
  104.             else {
  105.                 for (; c >= '0' && c <= '9'; c = *++fmt)
  106.                     F.precision = (10 * F.precision) + (c - '0');
  107.             }
  108.             if (F.precision >= 0)
  109.                 F.havePrecision = TRUE;
  110.         }
  111.         
  112.             /*  perform appropriate conversion  */
  113.         
  114.         s = &buf[BUFLEN];
  115.         if (F.leftJustify)
  116.             F.zeroPad = FALSE;
  117. conv:    switch (c) {
  118.                 
  119.                 /*  'h' size modifier  */
  120.                 
  121.             case 'h':
  122.                 F.hSize = TRUE;
  123.                 c = *++fmt;
  124.                 goto conv;
  125.                 
  126.                 /*  'l' size modifier  */
  127.                 
  128.             case 'l':
  129.                 F.lSize = TRUE;
  130.                 c = *++fmt;
  131.                 goto conv;
  132.                         
  133.                 /*  'L' size modifier  */
  134.                 
  135.             case 'L':
  136.                 F.LSize = TRUE;
  137.                 c = *++fmt;
  138.                 goto conv;
  139.         
  140.                 /*  decimal (signed)  */
  141.                 
  142.             case 'd':
  143.             case 'i':
  144.                 if (F.lSize)
  145.                     n = va_arg(arg, long);
  146.                 else
  147.                     n = va_arg(arg, int);
  148.                 if (F.hSize)
  149.                     n = (short) n;
  150.                 if ((long) n < 0) {
  151.                     n = -n;
  152.                     F.sign = '-';
  153.                 }
  154.                 else if (F.forceSign)
  155.                     F.sign = '+';
  156.                 goto decimal;
  157.                 
  158.                 /*  decimal (unsigned)  */
  159.                 
  160.             case 'u':
  161.                 if (F.lSize)
  162.                     n = va_arg(arg, unsigned long);
  163.                 else
  164.                     n = va_arg(arg, unsigned int);
  165.                 if (F.hSize)
  166.                     n = (unsigned short) n;
  167.                 F.sign = 0;
  168.                 goto decimal;
  169.                 
  170.                 /*  decimal (common code)  */
  171.  
  172.             decimal:
  173.                 if (!F.havePrecision) {
  174.                     if (F.zeroPad) {
  175.                         F.precision = F.fieldWidth;
  176.                         if (F.sign)
  177.                             --F.precision;
  178.                     }
  179.                     if (F.precision < 1)
  180.                         F.precision = 1;
  181.                 }
  182.                 for (i = 0; n; n /= 10, i++)
  183.                     *--s = n % 10 + '0';
  184.                 for (; i < F.precision; i++)
  185.                     *--s = '0';
  186.                 if (F.sign) {
  187.                     *--s = F.sign;
  188.                     i++;
  189.                 }
  190.                 break;
  191.                 
  192.                 /*  octal (unsigned)  */
  193.                 
  194.             case 'o':
  195.                 if (F.lSize)
  196.                     n = va_arg(arg, unsigned long);
  197.                 else
  198.                     n = va_arg(arg, unsigned int);
  199.                 if (F.hSize)
  200.                     n = (unsigned short) n;
  201.                 if (!F.havePrecision) {
  202.                     if (F.zeroPad)
  203.                         F.precision = F.fieldWidth;
  204.                     if (F.precision < 1)
  205.                         F.precision = 1;
  206.                 }
  207.                 for (i = 0; n; n /= 8, i++)
  208.                     *--s = n % 8 + '0';
  209.                 if (F.altForm && i && *s != '0') {
  210.                     *--s = '0';
  211.                     i++;
  212.                 }
  213.                 for (; i < F.precision; i++)
  214.                     *--s = '0';
  215.                 break;
  216.                 
  217.                 /*  hexadecimal (unsigned)  */
  218.                 
  219.             case 'p':
  220.                 F.havePrecision = F.lSize = TRUE;
  221.                 F.precision = 8;
  222.                 /* ... */
  223.             case 'X':
  224.                 digits = "0123456789ABCDEF";
  225.                 goto hexadecimal;
  226.             case 'x':
  227.                 digits = "0123456789abcdef";
  228.                 /* ... */
  229.             hexadecimal:
  230.                 if (F.lSize)
  231.                     n = va_arg(arg, unsigned long);
  232.                 else
  233.                     n = va_arg(arg, unsigned int);
  234.                 if (F.hSize)
  235.                     n = (unsigned short) n;
  236.                 if (!F.havePrecision) {
  237.                     if (F.zeroPad) {
  238.                         F.precision = F.fieldWidth;
  239.                         if (F.altForm)
  240.                             F.precision -= 2;
  241.                     }
  242.                     if (F.precision < 1)
  243.                         F.precision = 1;
  244.                 }
  245.                 for (i = 0; n; n /= 16, i++)
  246.                     *--s = digits[n % 16];
  247.                 for (; i < F.precision; i++)
  248.                     *--s = '0';
  249.                 if (F.altForm) {
  250.                     *--s = c;
  251.                     *--s = '0';
  252.                     i += 2;
  253.                 }
  254.                 break;
  255.                 
  256. #ifndef _NOFLOATING_
  257.                 /*  fixed-point  */
  258.  
  259.             case 'f':
  260.                 if (F.LSize)
  261.                     x = va_arg(arg, long double);
  262.                 else
  263.                     x = va_arg(arg, double);
  264.                 if (!F.havePrecision)
  265.                     F.precision = 6;
  266.                 ftod(1, F.precision, &D, x);
  267.                 D.dot = D.exp + D.sig[0];
  268.                 if ((D.min = D.dot) > 1)
  269.                     D.min = 1;
  270.                 D.max = D.dot + F.precision;
  271.                 if (D.max - D.min > 508)
  272.                     memcpy(D.sig, "\6>>>>>>", 7);
  273.                 goto floating;
  274.  
  275.                 /*  floating-point  */
  276.                 
  277.             case 'e':
  278.             case 'E':
  279.                 if (F.LSize)
  280.                     x = va_arg(arg, long double);
  281.                 else
  282.                     x = va_arg(arg, double);
  283.                 if (!F.havePrecision)
  284.                     F.precision = 6;
  285.                 F.exponent = c;
  286.                 ftod(0, D.max = F.precision + 1, &D, x);
  287.                 D.min = D.dot = 1;
  288.                 D.exp += D.sig[0] - 1;
  289.                 goto floating;
  290.                 
  291.                 /*  "general" notation  */
  292.                 
  293.             case 'g':
  294.             case 'G':
  295.                 if (F.LSize)
  296.                     x = va_arg(arg, long double);
  297.                 else
  298.                     x = va_arg(arg, double);
  299.                 if (!F.havePrecision)
  300.                     F.precision = 6;
  301.                 else if (F.precision == 0)
  302.                     F.precision = 1;
  303.                 F.exponent = c - 2;
  304.                 ftod(0, D.max = F.precision, &D, x);
  305.                 D.min = D.dot = 1;
  306.                 D.exp += D.sig[0] - 1;
  307.                 if (D.exp >= -4 && D.exp < F.precision) {
  308.                     F.exponent = 0;
  309.                     if ((D.dot += D.exp) < 1)
  310.                         D.min = D.dot;
  311.                 }
  312.                 if (!F.altForm && D.max > D.sig[0]) {
  313.                     if ((D.max = D.sig[0]) < D.dot)
  314.                         D.max = D.dot;
  315.                 }
  316.                 goto floating;
  317.                 
  318.                     /*  floating (common code)  */
  319.  
  320.             floating:
  321.                 if (D.sig[1] > '9') {
  322.                     F.exponent = FALSE;
  323.                     D.dot = 0;
  324.                     D.min = 1;
  325.                     D.max = D.sig[0];
  326.                 }
  327.                 i = 0;
  328.                 if (F.exponent) {
  329.                     n = D.exp < 0 ? -D.exp : D.exp;
  330.                     for (; n; n /= 10, i++)
  331.                         *--s = n % 10 + '0';
  332.                     for (; i < 2; i++)
  333.                         *--s = '0';
  334.                     *--s = D.exp < 0 ? '-' : '+';
  335.                     *--s = F.exponent;
  336.                     i += 2;
  337.                 }
  338.                 j = D.max;
  339.                 if (j == D.dot && !F.altForm)
  340.                     ++D.dot;
  341.                 do {
  342.                     if (j == D.dot) {
  343.                         *--s = '.';
  344.                         i++;
  345.                     }
  346.                     *--s = j > 0 && j <= D.sig[0] ? D.sig[j] : '0';
  347.                 } while (--j >= D.min);
  348.                 i += D.max - j;
  349.                 if (D.sgn)
  350.                     F.sign = '-';
  351.                 else if (F.forceSign)
  352.                     F.sign = '+';
  353.                 if (F.zeroPad) {
  354.                     j = F.fieldWidth;
  355.                     if (F.sign)
  356.                         --j;
  357.                     for (; i < j; i++)
  358.                         *--s = '0';
  359.                 }
  360.                 if (F.sign) {
  361.                     *--s = F.sign;
  362.                     i++;
  363.                 }
  364.                 break;
  365. #endif _NOFLOATING_
  366.  
  367.                 /*  character  */
  368.                 
  369.             case 'c':
  370.                 *--s = va_arg(arg, int);
  371.                 i = 1;
  372.                 break;
  373.                 
  374.                 /*  string  */
  375.                 
  376.             case 's':
  377.                 s = va_arg(arg, char *);
  378.                 if (F.altForm) {
  379.                     i = (unsigned char) *s++;
  380.                     if (F.havePrecision && i > F.precision)
  381.                         i = F.precision;
  382.                 }
  383.                 else {
  384.                     if (!F.havePrecision)
  385.                         i = strlen(s);
  386.                     else if (t = memchr(s, '\0', F.precision))
  387.                         i = t - s;
  388.                     else
  389.                         i = F.precision;
  390.                 }
  391.                 break;
  392.                 
  393.                 /*  store # bytes written so far  */
  394.                 
  395.             case 'n':
  396.                 s = va_arg(arg, void *);
  397.                 if (F.hSize)
  398.                     * (short *) s = nwritten;
  399.                 else if (F.lSize)
  400.                     * (long *) s = nwritten;
  401.                 else
  402.                     * (int *) s = nwritten;
  403.                 continue;
  404.             
  405.                 /*  oops - unknown conversion, abort  */
  406.                 
  407.             default:
  408.                 if (c != '%')
  409.                     goto done;
  410.             copy1:
  411.                 if (putc(c, fp) < 0)
  412.                     return(EOF);
  413.                 ++nwritten;
  414.                 continue;
  415.         }
  416.             
  417.             /*  pad on the left  */
  418.             
  419.         if (i < F.fieldWidth && !F.leftJustify) {
  420.             do {
  421.                 if (putc(' ', fp) < 0)
  422.                     return(EOF);
  423.                 ++nwritten;
  424.             } while (i < --F.fieldWidth);
  425.         }
  426.         
  427.             /*  write the converted result  */
  428.             
  429.         if (fwrite(s, 1, i, fp) != i)
  430.             return(EOF);
  431.         nwritten += i;
  432.             
  433.             /*  pad on the right  */
  434.             
  435.         for (; i < F.fieldWidth; i++) {
  436.             if (putc(' ', fp) < 0)
  437.                 return(EOF);
  438.             ++nwritten;
  439.         }
  440.     }
  441.     
  442.         /*  all done!  */
  443.         
  444. done:
  445.     return(nwritten);
  446. }
  447.  
  448.  
  449. /* ---------- floating-point conversion ---------- */
  450.  
  451. #ifndef _NOFLOATING_
  452. static void
  453. ftod(int fixed, int precision, struct decrec *d, long double x)
  454. {
  455.     struct { char style; short digits; } form;
  456.     int i;
  457.     register short *p = (short *) &x;
  458.     
  459.         /*  point to SANE extended  */
  460.  
  461. #if __option(mc68881) && __option(native_fp)
  462.     p[1] = p[0];
  463. #endif
  464. #if __option(mc68881) || !__option(native_fp)
  465.     p++;
  466. #endif
  467.     
  468.         /*  convert to decimal record  */
  469.     
  470.     if (precision >= sizeof d->sig)
  471.         precision = sizeof d->sig - 1;
  472.     form.style = fixed;
  473.     form.digits = precision;
  474.     fp68k(&form, p, d, (short)FX2DEC);
  475.     
  476.         /*  handle fixed-point overflow  */
  477.         
  478.     if (d->sig[1] == '?') {
  479.         form.style = 0;
  480.         form.digits = sizeof d->sig - 1;
  481.         fp68k(&form, p, d, (short)FX2DEC);
  482.     }
  483.     
  484.         /*  strip trailing zeroes  */
  485.         
  486.     for (i = d->sig[0]; i > 1 && d->sig[i] == '0'; --i)
  487.         ++d->exp;
  488.     d->sig[0] = i;
  489.         
  490.         /*  format 0, INF, NAN  */
  491.         
  492.     if (d->sig[1] == '0') {
  493.         d->sgn = 0;        /*  delete to allow printing "-0"  */
  494.         d->exp = 0;
  495.     }
  496.     else if (d->sig[1] == 'I') {
  497.         d->sig[0] = 3;
  498.         d->sig[2] = 'N';
  499.         d->sig[3] = 'F';
  500.     }
  501.     else if (d->sig[1] == 'N') {
  502.         d->sig[0] = 5;
  503.         d->sig[2] = 'A';
  504.         d->sig[3] = 'N';
  505.     }
  506. }
  507. #endif _NOFLOATING_
  508.